// areaeditor.cpp : contains the window class to create and modify area files
//$Id: AreaEditor.cpp 47 2009-09-26 21:05:06Z brwarner2 $

#include "StdAfx.h"
#include "AreaEditor.h"
#include "resource.h"

CAreaEditor::CAreaEditor(void)
{
}

CAreaEditor::~CAreaEditor(void)
{
}
//Level preview classname
const static char LEVELVIEW_CLASS[] = "levelview_wnd";

void CAreaEditor::RegisterClasses(void)
{
	WNDCLASSEX wc;
	SecureZeroMemory(&wc, sizeof(wc));
	wc.cbSize = sizeof(wc);
	wc.hbrBackground = 0;
	wc.hCursor = LoadCursor(0, IDC_ARROW);
	wc.hInstance = GetModuleHandle(0);
	wc.lpfnWndProc = LevelPreviewCallback;
	wc.lpszClassName = LEVELVIEW_CLASS;
	RegisterClassEx(&wc);
}

BOOL CALLBACK CAreaEditor::CreateObjectDialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
		//Dialog initialization
	case WM_INITDIALOG:
		{
			//Load objects
			ObjectTypeList objects = LoadObjectList();

			//Fill combo box
			for( ObjectTypeList::iterator iter = objects.begin(); iter != objects.end(); iter++ )
			{
				SendMessage( GetDlgItem(hWnd, IDC_OBJECT_TYPE), CB_ADDSTRING, 0, (LPARAM)iter->first.c_str() );
			}

			//Save the output buffer
			SetWindowLongPtr( hWnd, GWLP_USERDATA, lParam );
		}break;
	case WM_COMMAND:
		{
			switch(LOWORD(wParam))
			{
			case IDOK:
				{
					//Get selected item
					int index = SendMessage( GetDlgItem(hWnd, IDC_OBJECT_TYPE), CB_GETCURSEL, 0, 0 );
					if( index == CB_ERR ) 
					{
						MessageBox(hWnd, "Please select a valid item", "Item Selection", MB_ICONERROR);
					}
					else
					{
						//Get the item text
						int textLength = SendMessage( GetDlgItem(hWnd, IDC_OBJECT_TYPE), CB_GETLBTEXTLEN, index, 0 );

						//Create buffer
						char* buffer = new char[textLength+1];
						SendMessage( GetDlgItem(hWnd, IDC_OBJECT_TYPE), CB_GETLBTEXT, index, (LPARAM)buffer );

						//Send buffer away
						(*(char**)(GetWindowLongPtr( hWnd, GWLP_USERDATA ) )) = buffer;
						EndDialog(hWnd, IDOK);
					}
				}break;
			}
		}break;
	default:
		return FALSE;
	}
	return TRUE;
}

LRESULT CALLBACK CAreaEditor::LevelPreviewCallback(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
#define GetLevelInfo() reinterpret_cast<LevelInfo*>(GetWindowLongPtr( hWnd, GWLP_USERDATA ))
	switch(msg)
	{
	case WM_CREATE:
		{
			//Create the level information structure
			LevelInfo* pInfo = new LevelInfo();
			SecureZeroMemory(pInfo, sizeof(LevelInfo));
			SetWindowLongPtr( hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pInfo) );

			//Create the menus
			pInfo->hParentMenu = LoadMenu( GetModuleHandle(0), MAKEINTRESOURCE(IDR_OBJMENU) );
			pInfo->hClickMenu = GetSubMenu(pInfo->hParentMenu, 0);
		}break;
	case WM_SETSPRITE:
		{
			//Save sprite
			GetLevelInfo()->pSprite = reinterpret_cast<Gdiplus::Image*>(lParam);
		}break;
	case WM_GIVEHANDLE:
		{
			GetLevelInfo()->pObjects = reinterpret_cast<ObjectList*>(lParam);
			ObjectList* pObjs = GetLevelInfo()->pObjects;

			//Load sprites
			for( ObjectList::iterator iter = pObjs->begin(); iter != pObjs->end(); iter++ )
			{
				Object* pObj = (*iter);
				if( pObj->properties.find("texture") != pObj->properties.end() )
				{
					//Load image
					Gdiplus::Image* pImg = LoadImageFromFile( pObj->properties["texture"] );
					pObj->pSprite = pImg;

					//Load position
					std::string pos = pObj->properties.find("position")->second;
					std::stringstream str(pos);
					unsigned int x, z;
					str >> x >> z;
					pObj->hitRect.top = z; pObj->hitRect.left = x;

					//Load image information (width)
					unsigned w = GetWidth( pObj->properties["texture"] + ".info"), h = GetHeight( pObj->properties["texture"] + ".info");
					pObj->hitRect.bottom = z + h; pObj->hitRect.right = x + w;
				}
			}

			//Sort
			//Sort
			SendMessage(hWnd, WM_SORTLIST, 0, 0);
		}break;
	case WM_PAINT:
		{
			if( GetLevelInfo()->pSprite == 0 ) break;
			LevelInfo* pInfo = GetLevelInfo();

			//Begin paint
			PAINTSTRUCT ps;
			HDC hdc = BeginPaint(hWnd, &ps);
			using namespace Gdiplus;

			//Start graphics
			Graphics g(hdc);
			//g.Clear(Color(255,255,255));

			//Draw background
			g.DrawImage( pInfo->pSprite, 0, 0 );
			Pen p(Color(0, 0, 0));
			g.DrawRectangle(&p, 0, 0, pInfo->pSprite->GetWidth()-1, pInfo->pSprite->GetHeight()-1);

			//Draw objects
			for( ObjectList::iterator iter = pInfo->pObjects->begin(); iter != pInfo->pObjects->end(); iter++ )
			{
				//Get object
				Object* pObj = (*iter);

				//Create GDIRect
				Gdiplus::Rect rc(pObj->hitRect.left, pObj->hitRect.top, pObj->hitRect.right - pObj->hitRect.left,
					pObj->hitRect.bottom - pObj->hitRect.top);
				
				//Draw image
				g.DrawImage(pObj->pSprite, rc, 0, 0, rc.GetRight()-rc.GetLeft(), rc.GetBottom()-rc.GetTop(), UnitPixel);
			}

			//End paint
			EndPaint(hWnd, &ps);
		}break;
	case WM_LBUTTONDOWN:
		{
			//Find out what object was hit
			LevelInfo* pInfo = GetLevelInfo();
			POINT p;
			p.x = LOWORD(lParam);
			p.y = HIWORD(lParam);

			//For each object
			for( ObjectList::reverse_iterator iter = pInfo->pObjects->rbegin(); iter != pInfo->pObjects->rend(); iter++ )
			{
				//Get object
				Object* pObj = (*iter);

				//Check intersect
				if( PtInRect(&pObj->hitRect, p) )
				{
					//Set draggy
					pInfo->pDrag = pObj;
					pInfo->offsetX = p.x - pObj->hitRect.left;
					pInfo->offsetY = p.y - pObj->hitRect.top;

					//Send click notify
					NMHDSELECTINFO hdr2;
					hdr2.hdr.code = LVLN_SELECT;
					hdr2.hdr.hwndFrom = hWnd;
					hdr2.hdr.idFrom = GetDlgCtrlID(hWnd);
					LevelInfo* pInfo = GetLevelInfo();
					hdr2.objID = pInfo->pObjects->size()-std::distance(pInfo->pObjects->rbegin(), iter)-1;
					SendMessage(GetParent(hWnd), WM_NOTIFY, (WPARAM)hWnd, reinterpret_cast<LPARAM>(&hdr2));
					break;
				}
			}
		}break;
	case WM_LBUTTONUP:
		{
			GetLevelInfo()->pDrag = 0;
		}break;
	case WM_MOUSEMOVE:
		{
			//Get level info
			LevelInfo* pInfo = GetLevelInfo();

			//Check for drag
			if( pInfo->pDrag )
			{
				//Set position
				POINT p;
				p.x = LOWORD(lParam) - pInfo->offsetX;
				p.y = HIWORD(lParam) - pInfo->offsetY;
				pInfo->pDrag->properties["position"] = boost::lexical_cast<std::string>(p.x) + " " + boost::lexical_cast<std::string>(p.y);
				RECT rcold = pInfo->pDrag->hitRect;

				//Set hit rect
				UpdateHitRect(&pInfo->pDrag->hitRect, p.x, p.y);

				//Update rect
				RECT upRect;
				UnionRect(&upRect, &pInfo->pDrag->hitRect, &rcold);
				InvalidateRect(hWnd, &upRect, 0);

				//Refresh the list view
				InvalidateRect(GetDlgItem(GetParent(hWnd), IDLV_PROP), 0, 0);
				UpdateWindow(GetDlgItem(GetParent(hWnd), IDLV_PROP));

				//Sort
				SendMessage(hWnd, WM_SORTLIST, 0, 0);
			}
		}break;
	case WM_DESTROY:
		{
			//Delete background sprite
			LevelInfo *pInfo = GetLevelInfo();
			DestroyMenu(pInfo->hParentMenu);
			pInfo->hClickMenu = 0;
			delete pInfo->pSprite;
			delete pInfo;
			SetWindowLongPtr( hWnd, GWLP_USERDATA, 0 );
		}break;
	case WM_CONTEXTMENU:
		{
			//Get level info
			LevelInfo* pInfo = GetLevelInfo();
			TrackPopupMenu(pInfo->hClickMenu, 0, LOWORD(lParam), HIWORD(lParam), 0, hWnd, 0);
		}break;
	case WM_SORTLIST:
		{
			std::sort( GetLevelInfo()->pObjects->begin(), GetLevelInfo()->pObjects->end(), SortPrep );
		}break;
	case WM_COMMAND:
		{
			switch(LOWORD(wParam))
			{
			case IDM_CREATE_OBJECT_HERE1:
				{
					//Get the object typename
					char* buffer = 0;
					int ret = DialogBoxParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_CREATEOBJECT), GetParent(hWnd), CreateObjectDialogProc, (LPARAM)&buffer);
					
					//Load the object list
					ObjectTypeList types = LoadObjectList();
					
					//Lookup type
					std::list<std::string> tpl = types[buffer];

					//Create object structure
					Object *pObj = new Object();
					pObj->type = buffer;
					for( std::list<std::string>::iterator iter = tpl.begin(); iter != tpl.end(); iter++ )
					{
						std::string prop = *iter;
						pObj->properties[prop] = "";

						//Special cases
						if( prop == "position" ) pObj->properties[prop] = "50 50";
						else if(prop == "texture" ) pObj->properties[prop] = "door.png";
					}
					
					//Load the sprite
					pObj->pSprite = LoadImageFromFile(pObj->properties["texture"]);
					
					//Setup hit rect
					std::string pos = pObj->properties.find("position")->second;
					std::stringstream str(pos);
					unsigned int x, z;
					str >> x >> z;
					pObj->hitRect.top = z; pObj->hitRect.left = x;

					//Load image information (width)
					unsigned w = GetWidth( pObj->properties["texture"] + ".info"), h = GetHeight( pObj->properties["texture"] + ".info");
					pObj->hitRect.bottom = z + h; pObj->hitRect.right = x + w;

					//Add the object
					GetLevelInfo()->pObjects->push_back(pObj);

					//Redraw
					InvalidateRect(hWnd, 0, TRUE);
				}break;
			}
		}break;
	default:
		return DefWindowProc(hWnd, msg, wParam, lParam);
	}
	return 0;
#undef GetLevelInfo
}

bool CAreaEditor::SortPrep( Object* pObj1, Object* pObj2 )
{
	//Get both y co-ordinates
	unsigned int y1 = pObj1->hitRect.bottom, y2 = pObj2->hitRect.bottom;

	//Return which is bigger
	return y1 < y2;
}

unsigned int CAreaEditor::GetWidth( const std::string& filename )
{
	do
	{
		std::ifstream info(filename.c_str());
		if(info.fail()) break;
		using namespace std;
		string line;
		while(getline(info, line))
		{
			stringstream str = stringstream(line);
			string name;
			getline(str,name, ':');
			unsigned int value;
			str >> value;

			/*if(name == "frames") m_nFrames = value;*/
			if(name == "frame-size") return value;
			/*else if(name == "frame-rate") m_nFPS = value;
			else if(name == "height") m_height = value;*/
		}
		info.close();
	}while(false);
	return 0;
}

unsigned int CAreaEditor::GetHeight( const std::string& filename )
{
	do
	{
		std::ifstream info(filename.c_str());
		if(info.fail()) break;
		using namespace std;
		string line;
		while(getline(info, line))
		{
			stringstream str = stringstream(line);
			string name;
			getline(str,name, ':');
			unsigned int value;
			str >> value;

			/*if(name == "frames") m_nFrames = value;*/
			if(name == "height") return value;
			/*else if(name == "frame-rate") m_nFPS = value;
			else if(name == "height") m_height = value;*/
		}
		info.close();
	}while(false);
	return 0;
}

void CAreaEditor::CreateControls( void )
{
	//Get instance to application for creating controls
	HINSTANCE hInstance = GetModuleHandle(0);

	//Create preview control
	m_hLevel = CreateWindowEx(0, LEVELVIEW_CLASS, "", WS_CHILD | WS_VISIBLE, 20, 20, 100, 100, m_hWindow, 0, hInstance, 0);

	//Create list view properties
	m_hProperties = CreateWindowEx(0 , WC_LISTVIEW, 0, WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_OWNERDATA, 0, 0, 250, 150, m_hWindow, (HMENU)IDLV_PROP, hInstance, 0);
	ListView_SetExtendedListViewStyle(m_hProperties, LVS_EX_FULLROWSELECT);

	//Column names
	char nameText[] = "Property";
	char valueText[] = "Value";

	//Create column structures
	LVCOLUMN col;
	col.mask = LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
	col.cx = 100;
	col.pszText = nameText;
	col.iSubItem = 0;
	ListView_InsertColumn(m_hProperties, 0, &col);

	col.pszText = valueText;
	col.iSubItem = 1;
	ListView_InsertColumn(m_hProperties, 1, &col);
}

BOOL EnumObjectProc( HWND hWnd, LPARAM lParam )
{
	//Get area editor
	CAreaEditor* pAreaEditor = reinterpret_cast<CAreaEditor*>(lParam);
	return pAreaEditor->SortObjects( hWnd );
}

BOOL CAreaEditor::SortObjects( HWND hWnd )
{
	//Make a copy of the Object List
	/*ObjectList newList = m_objects;


	//If this is the start, enumarate windows
	if( hWnd == 0 ) {*/
		/*EnumChildWindows(m_hLevel, EnumObjectProc, reinterpret_cast<LPARAM>(this));*/
		/*return TRUE;
	}

	//Get the object info
	ObjectInfo* pInfo = reinterpret_cast<ObjectInfo*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
	std::stringstream str(pInfo->pObj->properties["position"]);
	unsigned int x, y;
	str >> x >> y;*/
	return TRUE;
}

LRESULT CAreaEditor::Message(UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
	case WM_CREATE:
		{
			m_pSelected = 0;

			//Create child controls
			CreateControls();
		}break;
	case WM_NOTIFY:
		{
			LPNMHDR hdr = reinterpret_cast<LPNMHDR>(lParam);
			if( hdr->code == LVLN_SELECT )
			{
				NMHDSELECTINFO* pInfo = reinterpret_cast<NMHDSELECTINFO*>(lParam);

				//Get object
				Object* pObj = m_objects[pInfo->objID];
				ListView_DeleteAllItems(m_hProperties);
				ListView_SetItemCountEx(m_hProperties, pObj->properties.size(), 0);
				m_pSelected = pObj;
			}
			else if( hdr->code == LVN_GETDISPINFO )
			{
				//Get display info structure
				NMLVDISPINFO* hddi = reinterpret_cast<NMLVDISPINFO*>(lParam);
				if( hddi->item.mask & LVIF_TEXT )
				{
					//Get iterator to position
					Object::ParameterList::iterator iter = m_pSelected->properties.begin();
					std::advance(iter,hddi->item.iItem);

					//Check subitem
					if( hddi->item.iSubItem == 0 )
					{
						//Save property name
						strcpy(hddi->item.pszText, iter->first.c_str());
					}
					else if( hddi->item.iSubItem == 1 )
					{
						//Save property value
						strcpy(hddi->item.pszText, iter->second.c_str());
					}
				}
			} else if( hdr->code == NM_DBLCLK  && hdr->hwndFrom == m_hProperties )
			{
				//Get the item information and fill an intem index structure
				LPNMITEMACTIVATE lpitem = reinterpret_cast<LPNMITEMACTIVATE>(lParam);
				
				//Get the bounding rectangle
				RECT rc;
				SecureZeroMemory(&rc, sizeof(rc));
				ListView_GetSubItemRect(m_hProperties, lpitem->iItem, 1,
					LVIR_LABEL,&rc);

				//Get width and height
				unsigned int width = rc.right-rc.left, height = rc.bottom-rc.top;

				//Get proper position
				POINT p;
				p.x = rc.left; p.y = rc.top;
				ClientToScreen(m_hProperties, &p);
				ScreenToClient(m_hWindow, &p);

				//Create a text box ontop
				HFONT hFont = (HFONT)SendMessage(m_hProperties, WM_GETFONT, 0, 0);
				m_hPropertyEdit = CreateWindowEx(0, WC_EDIT, "test", WS_VISIBLE | WS_CHILD | WS_BORDER, p.x, p.y, width, height, m_hWindow, (HMENU)IDE_PROPEDIT,
					GetModuleHandle(0), 0);
				SendMessage(m_hPropertyEdit, WM_SETFONT, (WPARAM)hFont, TRUE);
				SetFocus(m_hPropertyEdit);

				//Get the property value selected
				Object::ParameterList::iterator iter = m_pSelected->properties.begin();
				std::advance(iter, lpitem->iItem);

				//Save name of item
				m_editItemName = iter->first;
				SetWindowText(m_hPropertyEdit, iter->second.c_str());
				Edit_SetHilite(m_hPropertyEdit, 0, iter->second.length());
				
			}
		}break;
	case WM_COMMAND:
		{
			//On edit control lose focus
			if( LOWORD(wParam) == IDE_PROPEDIT && HIWORD(wParam) == EN_KILLFOCUS)
			{
				//Get the edit control text
				unsigned int len = GetWindowTextLength(m_hPropertyEdit)+1;
				char *buffer = new char[len];
				GetWindowText(m_hPropertyEdit, buffer, len);

				//Set the property name
				m_pSelected->properties[m_editItemName] = buffer;
				delete[] buffer;

				//Special position clause
				if(m_editItemName == "position")
				{
					unsigned int x, y;
					std::stringstream str(m_pSelected->properties["position"]);
					str >> x >> y;
					UpdateHitRect(&m_pSelected->hitRect, x, y);
					InvalidateRect( m_hLevel, 0, true );
				}
				else if(m_editItemName == "texture")
				{
					//Load new sprite
					delete m_pSelected->pSprite;
					m_pSelected->pSprite = LoadImageFromFile(m_pSelected->properties["texture"]);

					//Update the hit rect
					unsigned int w = GetWidth( m_pSelected->properties["texture"] + ".info" ), 
						h = GetHeight( m_pSelected->properties["texture"] + ".info" );
					m_pSelected->hitRect.right = m_pSelected->hitRect.left + w;
					m_pSelected->hitRect.bottom = m_pSelected->hitRect.top + h;
				}

				//Destroy the edit control
				m_editItemName = "";
				DestroyWindow(m_hPropertyEdit);
				m_hPropertyEdit = 0;
			}
			if( LOWORD(wParam) == IDM_SAVE_AREA1 )
			{
				//Get filename
				OPENFILENAME ofn;
				char szFileName[MAX_PATH] = "";
				ZeroMemory(&ofn, sizeof(ofn));

				ofn.lStructSize = sizeof(ofn);
				ofn.hwndOwner = m_hWindow;
				ofn.lpstrFilter = "Area Files (*.lvl)\0*.lvl\0";
				ofn.lpstrFile = szFileName;
				ofn.nMaxFile = MAX_PATH;
				ofn.hInstance = GetModuleHandle(0);
				ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
				ofn.lpstrDefExt = "lvl";

				//Save the old working directory
				char work[MAX_PATH+1];
				GetCurrentDirectory(MAX_PATH, work);

				//Open the dialog
				if(GetSaveFileName(&ofn))
				{
					//Save file
					SaveArea(szFileName);
				}

				//Refresh the old working directory
				SetCurrentDirectory(work);
			}
		}break;
	case WM_DESTROY:
		{
			//Destroy level viewer
			DestroyWindow(m_hLevel);

			//Destroy list view
			DestroyWindow(m_hProperties);

			//Destroy all objects
			for( ObjectList::iterator iter = m_objects.begin(); iter != m_objects.end(); iter++ )
			{
				//Get object
				Object* pObj = (*iter);
				delete pObj->pSprite;
				delete pObj;
			}
			m_objects.clear();
		}break;
	default:
		return DefWindowProc(m_hWindow, msg, wParam, lParam);
	}
	return 0;
}

void CAreaEditor::UpdateHitRect(LPRECT pRect, unsigned int x, unsigned int y)
{
	//Set hit rect
	unsigned int w = pRect->right - pRect->left, h = pRect->bottom - pRect->top;
	pRect->left = x; pRect->top = y;
	pRect->right = pRect->left + w;
	pRect->bottom = pRect->top + h;
}

CAreaEditor::ObjectTypeList CAreaEditor::LoadObjectList(void)
{
	//Create type list
	ObjectTypeList types;

	//Open the object file
	std::ifstream file("objects.ini");
	if(file.fail()) return types;

	using std::getline;
	using std::string;

	//While objects exist
	string type;
	while( getline(file, type) )
	{
		//Create list
		std::list<std::string> list;

		//Read until {
		string waste;
		getline(file, waste, '{');

		//Get body
		string body;
		getline(file, body, '}');
		getline(file, waste);
		std::stringstream strbody = std::stringstream(body);

		//Read each line
		string line;
		while( getline( strbody, line ) )
		{
			if(line.empty()) continue;

			//Save property
			list.push_back(line);
		}

		//Create object
		types[type] = list;
	}
	file.close();
	return types;
}

void CAreaEditor::LoadArea( const std::string& filename )
{
	//Open the area file
	std::ifstream file(filename.c_str());
	if(file.fail()) return;

	using std::getline;
	using std::string;

	//Read background name
	getline(file, m_backgroundName);

	//While objects exist
	string type;
	while( getline(file, type) )
	{
		//Create object
		Object *obj = new Object();
		obj->type = type;

		//Read until {
		string waste;
		getline(file, waste, '{');

		//Get body
		string body;
		getline(file, body, '}');
		getline(file, waste);
		std::stringstream strbody = std::stringstream(body);

		//Read each line
		string line;
		while( getline( strbody, line ) )
		{
			if(line.empty()) continue;

			//Name to the :
			string name = line.substr(0, line.find_first_of(':'));

			//Value to the end
			string value = line.substr(line.find_first_of(':') + 1);

			//Add to parameter
			obj->properties[name] = value;
		}

		//Create object
		m_objects.push_back(obj);
	}
	file.close();

	//Set background
	Gdiplus::Image* pBack = LoadImageFromFile(m_backgroundName);
	SetWindowPos(m_hProperties, 0, 20+pBack->GetWidth()+50, 20, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
	SendMessage( m_hLevel, WM_SETSPRITE, 0, reinterpret_cast<LPARAM>(pBack) );
	SetWindowPos( m_hLevel, 0, 0, 0, pBack->GetWidth(), pBack->GetHeight(), SWP_NOMOVE | SWP_NOZORDER );
	SetWindowPos( m_hWindow, 0, 0, 0, 20+pBack->GetWidth()+50+250+20, 20+pBack->GetHeight()+20, SWP_NOMOVE | SWP_NOZORDER );

	SendMessage( m_hLevel, WM_GIVEHANDLE, 0, reinterpret_cast<LPARAM>(&m_objects) );
	InvalidateRect( m_hLevel, 0, true);
}

void CAreaEditor::SaveArea( const std::string& filename )
{
	//Open file
	std::ofstream file(filename.c_str());
	if(file.fail()) return;

	using std::endl;

	//Write background name
	file << m_backgroundName << endl;

	//For each object
	for( ObjectList::iterator iter = m_objects.begin(); iter != m_objects.end(); iter++ )
	{
		//Get object
		Object* pObj = (*iter);

		//Write type
		file << pObj->type << endl;
		file << "{" << endl;
		for( Object::ParameterList::iterator iter2 = pObj->properties.begin(); iter2 != pObj->properties.end(); iter2++ )
		{
			file << iter2->first << ':' << iter2->second << endl;
		}
		file << "}" << endl;
	}
	file.close();
}

void CAreaEditor::WindowInfo(::WindowInfo &info)
{
	info.windowName = "Area Editor";
	info.classname = "CAreaEditor";
	info.width = 500;
	info.height = 500;
	info.dwMenu = IDR_AREA;
}